#ifndef __M_BUFFER_H__
#define __M_BUFFER_H__

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include "../logs/log.h"


namespace Muduo
{
    const uint64_t defaultSize = 1024;
    class Buffer
    {
    public:
        Buffer(uint64_t size = defaultSize)
        :_buffer(size), _readIndex(0), _writeIndex(0)
        {}
        Buffer(const Buffer& other)
        :_buffer(other._buffer), _readIndex(other._readIndex), _writeIndex(other._writeIndex)
        {}
        Buffer& operator=(const Buffer& other)
        {
            if(&other != this)
            {
                _buffer = other._buffer;
                _readIndex = other._readIndex;
                _writeIndex = other._writeIndex;
            }
            return *this;
        }
        ~Buffer()
        {}
        //获取当前写入起始位置
        char* WritePosition()
        {
            return &_buffer[_writeIndex];
        }
        //获取当前读取起始位置
        const char* ReadPosition()const 
        {
            return &_buffer[_readIndex];
        }
        //获取当前读取起始位置
        char* ReadPosition()
        {
            return &_buffer[_readIndex];
        }
        //获取缓冲区末尾空闲空间大小---写位置之后的空闲空间
        uint64_t TailIdleSize()
        {
            return _buffer.size() - _writeIndex;
        }
        //获取缓冲区起始空闲空间大小---读位置之前的空闲空间
        uint64_t HeadIdleSize()
        {
            return _readIndex;
        }
        //获取可读数据大小
        uint64_t ReadAbleSize()
        {
            return _writeIndex - _readIndex;
        }
        //将读位置向后移动
        void MoveReadOffest(uint64_t len)
        {
            if(len == 0)
            {
                return;
            }
            if(_readIndex + len <= _writeIndex)
            {
                _readIndex += len;
            }
            else
            {
                LOGFATAL("读位置向后移动越界了！");
                exit(-1);
            }
        }
        //将写位置向后移动
        void MoveWriteOffest(uint64_t len)
        {
            EnsureWriteSpace(len);
            _writeIndex += len;
        }
        //确保可写空间足够(整体空闲空间足够就移动数据，不够就不移动数据直接扩容)
        void EnsureWriteSpace(uint64_t len)
        {
            //如果末尾空闲空间足够，则直接返回
            if(TailIdleSize() >= len)
            {
                return;
            }
            //如果整体空闲空间足够就移动数据
            uint64_t rsz = HeadIdleSize() + TailIdleSize();
            if(rsz >= len)
            {
                std::copy(ReadPosition(), WritePosition(), &_buffer[0]);
                uint64_t size = ReadAbleSize();
                _readIndex = 0;
                _writeIndex = size;
            }
            else//整体空闲空间不够直接扩容，不需要移动数据
            {
                _buffer.resize(_writeIndex + len);
            }
        }
        //写入数据
        void Write(const void* data, uint64_t len)
        {
            if(len == 0)
            {
                return;
            }
            //保证有足够的空间，之后将数据拷贝进去
            EnsureWriteSpace(len);
            const char* d = (const char*)data;
            std::copy(d, d+len, WritePosition());
        }
        //写入数据并push进去
        void WriteAndPush(const void* data, uint64_t len)
        {
            Write(data, len);
            //写位置向后偏移
            MoveWriteOffest(len);
        }
        void WriteString(const std::string& data)
        {
            Write(data.data(), data.size());
        }
        void WriteStringAndPush(const std::string& data)
        {
            WriteString(data);
            //写位置向后偏移
            MoveWriteOffest(data.size());
        }
        void WriteBuffer(Buffer& data)
        {
            return Write(data.ReadPosition(), data.ReadAbleSize());
        }
        void WriteBufferAndPush(Buffer& data)
        {
            WriteBuffer(data);
            //写位置向后偏移
            MoveWriteOffest(data.ReadAbleSize());
        }
        //读取数据
        void Read(void* buffer, uint64_t len)
        {
            //由于我们已经提供了获取可读数据大小的接口，那么我们必须要求读取数据的长度要小于等于可读数据大小
            if(len > ReadAbleSize())
            {
                LOGFATAL("读取的数据大小超过了可读数据大小！");
                exit(-1);
            }
            std::copy(ReadPosition(), ReadPosition()+len, (char*)buffer);
        }
        //读取数据并弹出读取了的数据
        void ReadAndPop(void* buffer, uint64_t len)
        {
            Read(buffer, len);
            //读位置向后偏移
            MoveReadOffest(len);
        }
        std::string ReadAsString(uint64_t len)
        {
            std::string str;
            str.resize(len);
            Read(&str[0], len);
            return str;
        }
        //读取数据并弹出读取了的数据
        std::string ReadAsStringAndPop(uint64_t len)
        {
            std::string str = ReadAsString(len);
            //读位置向后偏移
            MoveReadOffest(len);
            return str;
        }
        //寻找回车换行字符
        const char* FindCRLF()
        {
            const void* res = memchr(ReadPosition(), '\n', ReadAbleSize());
            return (const char*)res;
        }
        //通常获取一行数据，这种情况针对的是HTTP协议
        std::string GetLine()
        {
            const char* pos = FindCRLF();
            if(pos == nullptr)
            {
                LOGINFO("未找到换行字符！");
                return "";
            }
            //+1是为了将换行字符一起去出来
            return ReadAsString(pos - ReadPosition() + 1);
        }
        // 获取一行数据并弹出这一行数据
        std::string GetLineAndPop()
        {
            std::string str = GetLine();
            //读位置先后偏移
            MoveReadOffest(str.size());
            return str;
        }
        //清除缓冲区
        void Clear()
        {
            _readIndex = 0;
            _writeIndex = 0;
        }
    private:
        std::vector<char> _buffer;  //使用vector进行内存空间管理
        uint64_t _readIndex;    //读位置
        uint64_t _writeIndex;   //写位置
    };
}

#endif


